Remove fastly from trusted-server-core except the deferred EC KV/ERL subsystem (PR 15)#635
Conversation
BackendConfig uses fastly::backend::Backend directly, making it incompatible with the platform-portability goal. This commit: - Copies backend.rs verbatim into trusted-server-adapter-fastly, updating the one crate-internal import path - Adds url dependency to the adapter Cargo.toml - Rewires platform.rs and management_api.rs to use crate::backend - Removes pub mod backend from trusted-server-core/lib.rs - Migrates aps.rs, adserver_mock.rs, and prebid.rs off the deleted BackendConfig, using context.services.backend().ensure() for registration and a new predict_backend_name_for_url free function in integrations/mod.rs for stateless name prediction cargo check --workspace passes with zero errors.
All callers were migrated to predict_backend_name_for_url in core's integrations module. Remove the now-unused method and update the parse_origin doc comment that referenced it.
Remove crates/trusted-server-core/src/storage/ entirely (config_store.rs, secret_store.rs, mod.rs). All call sites migrated to PlatformConfigStore / PlatformSecretStore traits. Also drop the now-broken intra-doc links in trusted-server-adapter-fastly/src/platform.rs that referenced the deleted types.
Replace direct fastly::kv_store::KVStore usage in consent/kv.rs with a platform-neutral ConsentKvOps trait. The trait has four sync methods (load_entry, save_entry_with_ttl, fingerprint_unchanged, delete_entry) keeping the consent pipeline synchronous. - consent/kv.rs: add ConsentKvOps trait; replace load_consent_from_kv / save_consent_to_kv / delete_consent_from_kv with load_consent / save_consent (trait-based); remove open_store / fingerprint_unchanged private fns; drop ConsentKvMetadata / metadata_from_context (metadata API was Fastly-specific; fingerprint now lives in the body fp field); add StubKvOps + integration tests - consent/mod.rs: add kv_ops field to ConsentPipelineInput; update try_kv_fallback and try_kv_write to consume kv_ops instead of store_name; update all struct literal sites - publisher.rs: add kv_ops: Option<&dyn ConsentKvOps> parameter to handle_publisher_request; wire it into ConsentPipelineInput and use it for the SSC-revocation delete - adapter/platform.rs: add FastlyConsentKvStore wrapping fastly::kv_store::KVStore implementing ConsentKvOps via the sync API - adapter/app.rs + main.rs: open FastlyConsentKvStore from settings.consent.consent_store and pass as kv_ops to handle_publisher_request
Remove `fingerprint_unchanged` from `ConsentKvOps` trait so the common case (consent unchanged) costs one KV read instead of two. `save_consent` now loads the entry once and compares the fingerprint inline. Extract `open_consent_kv` helper in `app.rs` to deduplicate the two identical KV-open blocks. Replace bare `unwrap()` with descriptive `expect` messages in consent KV tests. Run `cargo fmt --all` to fix all whitespace issues.
Resolved five conflicts: - Deleted compat.rs (PR15 goal: remove Fastly from core) - integrations/mod.rs: kept both PR15's ensure_integration_backend_with_timeout / predict_backend_name_for_url and PR14's INTEGRATION_MAX_BODY_BYTES constant - integrations/adserver_mock.rs, aps.rs, prebid.rs: merged collect_body import (PR14) with ensure_integration_backend_with_timeout / predict_backend_name_for_url imports (PR15) into single use statements
aram356
left a comment
There was a problem hiding this comment.
Summary
This PR delivers its stated goal — trusted-server-core is now fully fastly-free and the consent pipeline is abstracted behind a minimal ConsentKvOps trait. Local verification passes (fmt, clippy -D warnings, cargo test --workspace, wasm32-wasip1 release build).
Three concerns merit changes before merge: a diagnostic regression in predict_backend_name_for_url, duplication of the security-adjacent SPOOFABLE_FORWARDED_HEADERS list, and a test-coverage regression in the relocated adapter compat.rs. The remaining items are non-blocking observations and follow-up candidates.
Note: this PR targets
feature/edgezero-pr14-entry-point-dual-path, notmain; review scope is the 31-file PR-15-specific delta (+2230/-2165).
Blocking
🔧 wrench
- Diagnostic regression in
predict_backend_name_for_url— inline comment atcrates/trusted-server-core/src/integrations/mod.rs:135 SPOOFABLE_FORWARDED_HEADERSduplicated across core and adapter — inline comment atcrates/trusted-server-adapter-fastly/src/compat.rs:18- Adapter
compat.rshas zero tests after relocation (14 security-relevant tests dropped) — inline comment atcrates/trusted-server-adapter-fastly/src/compat.rs:82
Non-blocking
🤔 thinking
- KV errors logged at
debuglevel as "lookup miss" — inline comment atcrates/trusted-server-adapter-fastly/src/platform.rs:420 - Backend-name compute logic duplicated between
predict_backend_name_for_url(core) andBackendConfig::compute_name(adapter) — inline comment atcrates/trusted-server-core/src/integrations/mod.rs:130
🌱 seedling
- Redundant KV read on fallback+save path — inline comment at
crates/trusted-server-core/src/consent/kv.rs:267 - Hardcoded
certificate_check: trueinensure_integration_backend(integrations/mod.rs:69) andensure_integration_backend_with_timeout(integrations/mod.rs:114). No regression vs. pre-PR behaviour, but the siblingpredict_backend_name_for_urldoes takecertificate_check: bool— asymmetric. If any integration ever needs a self-signed upstream (test/on-prem), these helpers would need to grow that parameter.
📌 out of scope
migration_guards.rsnot extended — migration_guards.rs:27-46 only covers 12 files and a narrow regex (Request|Response|http::Method|StatusCode|mime::APPLICATION_JSON). With core'sfastlydep now removed, this guard should either broaden to\bfastly::across all core files, be replaced by a Cargo-metadata dependency-presence test (more robust, no false negatives), or be deleted as structurally redundant. Follow-up issue.FastlyConsentKvStore::opensilent failure — inline comment atcrates/trusted-server-adapter-fastly/src/platform.rs:409
📝 note
- Stale "PR 15" forward references:
- adapter-fastly/src/app.rs:150: "will be removed when
legacy_mainis deleted in PR 15". This is PR 15 andlegacy_mainwas not deleted. - adapter-fastly/src/main.rs:113: "
compat.rswill be deleted in PR 15 once this legacy path is retired". This is PR 15;compat.rswas moved (not deleted) and the legacy path was not retired.
Update comments to reference the actual future PR number or drop the promise.
- adapter-fastly/src/app.rs:150: "will be removed when
⛏ nitpick
- Unnecessary
u16type suffix — inline comment atcrates/trusted-server-core/src/integrations/mod.rs:140
CI Status
- fmt: PASS
- clippy (
-D warnings): PASS - rust tests (
cargo test --workspace): PASS (800+ tests) - wasm32-wasip1 release build: PASS
- PR-reported checks (browser integration, integration tests, prepare integration artifacts): PASS
…mpat tests - predict_backend_name_for_url now returns Result<String, Report<TrustedServerError>> instead of Option<String>; call sites use inspect_err(...).ok() to preserve the Option<String> trait interface while logging the actual failure reason - Promote SPOOFABLE_FORWARDED_HEADERS to pub in http_util; replace inline copy in compat.rs with a use import — single source of truth for the strip list - Add sanitize_fastly_forwarded_headers_strips_spoofable test (all 4 entries + Host preserved) and to_fastly_response_with_streaming_body_produces_empty_body test (pins silent-drop behaviour) to compat.rs - Change Consent KV non-ItemNotFound error log from debug "lookup miss" to warn "lookup failed" for operational visibility - Drop stale "will be removed in PR 15" forward references from app.rs and main.rs - Drop unnecessary u16 type suffixes on port literal defaults
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
- Submitted reviewer-approved findings for consent/KV handling, backend naming consistency, and Fastly wiring.
- Verdict: REQUEST_CHANGES (includes a P1 finding).
Findings moved to review body
The following approved findings were included in the review body because GitHub could not resolve their requested inline locations in the current diff:
-
🤔 Consent bootstrap logic is now duplicated across auction and publisher paths (
crates/trusted-server-core/src/auction/endpoints.rs:61)
Both handlers now repeat the same sequence: parse cookies, generate/read synthetic ID, geo lookup with identical error handling, and build ConsentPipelineInput with kv_ops. This duplication is likely to drift as the consent pipeline evolves; this PR already had to touch both call sites just to thread the new abstraction through.
Suggestion: Extract a small shared helper that prepares request-scoped consent state once and returns the ConsentContext plus any reused intermediates such as synthetic_id, geo, and cookie_jar. -
⛏ Public docs/comments still lag the new kv_ops contract (
crates/trusted-server-core/src/auction/endpoints.rs:21)
The new kv_ops parameter materially changes how consent persistence is enabled, but the public docs still describe these handlers mostly in their pre-PR form, and one consent comment still says fallback requires consent_store rather than kv_ops.
Suggestion: Update the affected doc comments to explain that consent KV fallback/write-through occurs only when a concrete kv_ops implementation is supplied, and adjust the stale internal comment in consent/mod.rs.
|
Fixed the two findings GitHub moved into the review body in 3a53f33.
Fresh verification on this commit:
|
…ro-pr15-remove-fastly-core
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Summary
Approving this PR. The main refactor looks solid: trusted-server-core is decoupled from Fastly and the adapter now owns the Fastly-specific backend, KV, and compatibility wiring.
I left 2 non-blocking follow-up comments inline for logging/test coverage.
Incorporates the round-3 review fixes from PR14 (E2E tests, finalize-header coverage for unregistered methods, allowed_domains documentation) and the broader PR14 refactoring (EC ID rename from synthetic_id, kv_ops removal from handle_auction, runtime_services_for_consent_route consent KV approach, async tokio tests in proxy/orchestrator, PublisherResponse streaming). Conflict resolutions: - Take PR14's refactored core files (endpoints, orchestrator, consent, publisher, proxy, platform/mod, testlight) - Keep PR15's deletion of core/compat.rs and storage/mod.rs (Fastly code stays in adapter, not core) - Add from_fastly_response to adapter compat.rs (needed by EdgeZero path for entry-point finalize-header wrap introduced in PR14) - Remove obsolete FastlyConsentKvStore / open_consent_kv / ConsentKvOps references from platform.rs and app.rs (trait removed in PR14) - Fix orchestrator backend_name call to pass services (PR15 trait signature) - Add minimal backend.rs and storage/mod.rs stubs to core for DEFAULT_FIRST_BYTE_TIMEOUT and storage::kv_store module path - Add tokio as dev-dependency to trusted-server-core for async tests
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review of PR 15 after the most recent commits (Apr 27). The core refactor goal is achieved — trusted-server-core no longer imports fastly, and the migration guard test (migration_guards.rs) durably enforces the invariant. Build, clippy, fmt, and the full Rust test suite (878 tests) pass locally; GitHub CI is green.
However, the merge with PR14 removed the ConsentKvOps / FastlyConsentKvStore abstraction without replacing the wiring on the EdgeZero entry path, leaving a privacy-sensitive gap: when edgezero_enabled = true and consent_store is configured, consent revocation deletes silently fail. The PR description still describes the pre-merge design and is now misleading.
Requesting changes to address (or explicitly accept and document) the EdgeZero consent-KV gap and to update the PR description before merge.
Blocking
❓ question
Consent KV is not opened on the EdgeZero entry path — crates/trusted-server-adapter-fastly/src/app.rs:92
build_state() constructs kv_store = Arc::new(UnavailableKvStore) unconditionally, and build_per_request_services (lines 111–127) hands that same store to every handler. The runtime_services_for_consent_route helper in crates/trusted-server-adapter-fastly/src/main.rs:307-323 (which actually opens the configured consent.consent_store) is only called from the legacy route_request.
Consequence: when edgezero_enabled = true and [consent] consent_store = "..." is configured, every services.kv_store() call in core returns KvError::Unavailable. In particular, the revocation delete in crates/trusted-server-core/src/publisher.rs:765 silently fails (Failed to delete consent KV entry … Unavailable) — the EC cookie expires, but the persisted consent data is not removed. KV-backed consent fallback also never engages on the EdgeZero path. This is a privacy/compliance concern (right-to-erasure).
This appears to be a regression from the merge resolution that removed FastlyConsentKvStore / open_consent_kv after merging PR14. Either (a) the EdgeZero path needs an equivalent of runtime_services_for_consent_route (open the consent store inside build_per_request_services or wrap the auction/publisher handlers), or (b) the EdgeZero path should fail loudly at startup when consent.consent_store is configured but cannot be opened.
Was this intentional, or did it slip through the merge?
🔧 wrench
PR description is stale and contradicts the merged code — The body still claims:
- "Introduces a sync
ConsentKvOpstrait in core" - "
FastlyConsentKvStorein the adapter implements the trait" - "Threads
kv_ops: Option<&dyn ConsentKvOps>throughConsentPipelineInput"
None of these exist after the PR14 merge — the actual code uses PlatformKvStore directly via RuntimeServices, and the consent KV is opened only on the legacy path. The "Changes" table for consent/kv.rs, consent/mod.rs, app.rs, main.rs, and platform.rs describes work that was reverted. Reviewers and git log consumers will be misled. Please update the PR description to reflect the post-PR14-merge reality before merging.
Non-blocking
🤔 thinking
UnavailableKvStore swallows configuration errors silently on the EdgeZero path — Combined with the question above, configuring consent_store = "missing-store" on the EdgeZero path produces no startup error and only per-request warn! lines. The legacy path correctly fails the auction/publisher routes with 503 (verified by route_tests.rs:184). Worth validating consent-store availability at startup so misconfiguration cannot silently disable revocation.
⛏ nitpick
Pre-existing: core is on edition = "2021" — CLAUDE.md mandates 2024 edition. Not introduced by this PR; flagged only for awareness/follow-up.
CI Status
- fmt: PASS (local + GitHub)
- clippy: PASS (local,
-D warnings) - rust tests: PASS (878 tests, local)
- GitHub CI: PASS (browser tests, integration tests, prepare integration artifacts)
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review of PR 15 against HEAD 725ccdc2. Local verification passes (fmt, clippy -D warnings, 878 + 45 unit tests across the changed crates) and GitHub CI is green.
The core refactor goal is achieved — trusted-server-core no longer imports fastly and the migration guard test enforces the invariant. However, the previously flagged EdgeZero consent-KV regression (Apr 30 review) is still present at the same line, and the PR description still describes the pre-PR14-merge design that was reverted. Requesting changes to address (or explicitly accept and document) those before merge.
Blocking
🔧 wrench
-
EdgeZero path silently disables consent KV (privacy/compliance regression) —
crates/trusted-server-adapter-fastly/src/app.rs:92(line outside this PR's diff hunk, so flagging at body level).build_state()hardcodesArc::new(UnavailableKvStore), andbuild_per_request_services(lines 111–127) hands that exact store to every route. There is no analogue ofruntime_services_for_consent_route(main.rs:307-323) on this path.Concrete effect when
edgezero_enabled = trueAND[consent] consent_store = "..."is set:crates/trusted-server-core/src/publisher.rs:765callsdelete_consent_from_kv(services.kv_store(), cookie_ec_id), which hitsUnavailableKvStore.delete()→KvError::Unavailable.storage/kv_store.rs:323-332swallows the error (warn-log only). The EC cookie expires but the persisted consent is not removed — right-to-erasure broken.crates/trusted-server-core/src/auction/endpoints.rs:83-87andpublisher.rs:508-512passSome(services.kv_store())to the consent pipeline, but it's the unavailable store, so consent persistence and KV-backed consent fallback never engage.
Compare with the legacy path (correct):
route_tests.rs:184-260verifies that a missingconsent.consent_storeproduces a fail-closed 503 on/auctionand the publisher fallback viaroute_request. EdgeZero has no equivalent and silently degrades. Same blocking finding as the Apr 30 review, at the same line, still present at HEAD725ccdc2.Fix options:
- Open
consent.consent_storeinsidebuild_state()(or inbuild_per_request_services) usingplatform::open_kv_store, and either (a) fail startup if configured-but-unavailable or (b) wrap the consent-touching handlers (/auction, fallback) so they return 503 like the legacy path. - Mirror
runtime_services_for_consent_routeat the EdgeZero handler boundaries.
Either way, please add a counterpart of the existing
configured_missing_consent_store_only_breaks_consent_routestest that drivesTrustedServerApp::routes()so the regression cannot slip through another merge. -
PR description is stale and contradicts the merged code — the body still claims the PR introduces a sync
ConsentKvOpstrait, aFastlyConsentKvStoreadapter implementation, and threadskv_ops: Option<&dyn ConsentKvOps>throughConsentPipelineInput. None of those exist after the PR14 merge — the actual code usesPlatformKvStoredirectly viaRuntimeServices. The "Changes" table forconsent/kv.rs,consent/mod.rs,app.rs,main.rs, andplatform.rsdescribes work that was reverted. Please update the description to reflect the post-PR14-merge reality before merging so reviewers andgit logconsumers aren't misled.
Non-blocking
🤔 thinking
- No EdgeZero-side test for consent-store wiring —
route_tests.rs:184 configured_missing_consent_store_only_breaks_consent_routesonly exercises the legacyroute_request. There is no analogous test that constructsTrustedServerApp::routes()withconsent.consent_storeconfigured. Combined with the blocking finding above, the regression slipped through the PR14 merge with no failing test to catch it. - Both crates still on
edition = "2021"— CLAUDE.md mandates 2024 edition. Pre-existing across the repo, not introduced by this PR; flagged for awareness/follow-up.
📌 out of scope
UnavailableKvStoremakes consent-store misconfiguration invisible at startup — even after the blocking finding is addressed, configured-but-unopenable stores will only surface as per-requestwarn!lines unlessbuild_state()validates store availability at startup. Worth a follow-up to fail loudly whenconsent.consent_storeis set but cannot be opened.
CI Status
- fmt: PASS (local)
- clippy: PASS (local,
-D warnings) - rust tests: PASS (878 + 45 in changed crates)
- GitHub CI: PASS (browser tests, integration tests, prepare integration artifacts)
|
Addressed the body-level blocking findings from the Apr 30 and May 6 reviews in 50dc61f.
Fresh verification before commit:
|
aram356
left a comment
There was a problem hiding this comment.
Summary
This PR cleanly removes the fastly crate dependency from trusted-server-core, relocates the compat/backend layer into the adapter, migrates four integrations (aps, prebid, adserver_mock, sourcepoint) off BackendConfig to the platform-trait helpers, and restores the fail-closed consent KV wiring on the EdgeZero path for /auction and publisher fallback only. CI is green and local fmt/clippy/cargo test --workspace/wasm32-wasip1 build all pass.
Requesting changes on the items below — none are correctness-breaking today, but two of them (the select empty-backend-name fallback and the predict/ensure parameter asymmetry) sit on the bid-correlation path and can silently misbehave if upstream conditions shift.
Blocking
🤔 thinking — empty backend name silently propagates from select
crates/trusted-server-adapter-fastly/src/platform.rs:300-307 — when fastly_resp.get_backend_name() returns None, the code logs a warning and falls back to "". The PlatformResponse then carries backend_name == "", and AuctionOrchestrator correlates responses by exact string match against provider.backend_name(...). A bid response with "" will silently fail correlation — only the warning log signals the issue to operators.
Consider returning PlatformError::HttpClient here instead, so the orchestrator gets an explicit error frame for that bidder rather than a phantom non-match:
let ready = match result {
Ok(fastly_resp) => match fastly_resp.get_backend_name() {
Some(backend_name) => fastly_response_to_platform(fastly_resp, backend_name.to_string()),
None => Err(Report::new(PlatformError::HttpClient)
.attach("select: response has no backend name; correlation impossible")),
},
Err(e) => Err(Report::new(PlatformError::HttpClient)
.attach(format!("fastly select error: {e}"))),
};(Section unchanged in this PR, so flagging in body rather than inline — fix in this PR or open a follow-up.)
🌱 seedling — no compile-time guard that services.kv_store() is the consent KV
crates/trusted-server-core/src/publisher.rs:764-766 — correctness relies on the caller having threaded runtime_services_for_consent_route(...) before handle_publisher_request. Today the wiring is right (legacy route_request and EdgeZero dispatch_fallback's publisher branch both do it), but there's no compile-time guard. If a future entry point forgets, services.kv_store() will be UnavailableKvStore and delete will succeed-as-noop, leaving stale consent KV entries after a user revokes.
A typed ConsentKvStore(Arc<dyn PlatformKvStore>) newtype constructed only by runtime_services_for_consent_route would make the wiring mistake a compile error. Worth doing while this surface is fresh.
Non-blocking
♻️ refactor — duplicate enable_ssl().sni_hostname(self.host) in BackendConfig::ensure
crates/trusted-server-adapter-fastly/src/backend.rs:177-188 — enable_ssl().sni_hostname(self.host) is called once unconditionally, then a second time inside the if self.certificate_check branch before .check_certificate(host). Idempotent on the builder, so functionally fine, but easy to simplify on the file's move into the adapter:
builder = builder.enable_ssl().sni_hostname(self.host);
if self.certificate_check {
builder = builder.check_certificate(self.host);
} else {
log::warn!(
"INSECURE: certificate check disabled for backend: {}",
backend_name
);
}
log::info!("enable ssl for backend: {}", backend_name);Pre-existing in the deleted core copy; the relocation is the natural moment to clean it up. (Section unchanged in the rename diff, so flagging in body rather than inline.)
📝 note — AppState.kv_store is now always UnavailableKvStore
crates/trusted-server-adapter-fastly/src/app.rs:103 and the matching build_per_request_services site — per-route consent stores are opened on demand via runtime_services_for_consent_route, and no other consumer reads services.kv_store(). The field is now a placeholder, but its name reads as if it were the primary KV. Consider either inlining Arc::new(UnavailableKvStore) at the two construction sites, or renaming the field to default_kv_store to signal that it's only the fallback when no consent route override applies.
📝 note — three AuctionProvider::backend_name impls replicate identical bodies
aps.rs, prebid.rs, adserver_mock.rs all paste essentially the same body wrapping predict_integration_backend_name(&self.config.{endpoint,server_url}, …). A default method on AuctionProvider parameterised by (endpoint: &str, integration_id: &'static str) would remove the boilerplate; doing so would also make the dead certificate_check parameter (see the inline ♻️ refactor on integrations/mod.rs) impossible to misuse.
⛏ nitpick — from_fastly_request panics on URL parse failure
crates/trusted-server-adapter-fastly/src/compat.rs:11-28 — the deleted crates/trusted-server-core/src/compat.rs parsed the URL with a / fallback and warning log; this version .expects. Fastly delivers validated URLs in practice, and the # Panics doc is honest, so this is defensible — but the previous "log + continue" was strictly more defensive on a path that processes every inbound request. Preference call.
CI Status
- fmt: PASS
- clippy: PASS (no warnings)
- rust tests: PASS (950 + 54 + 21 + 3, doctests included)
- wasm32-wasip1 release build: PASS
- GitHub Actions: PASS (browser-integration, integration, prepare-integration-artifacts)
migration_guards.rsinvariant (nofastly::Request/Response/...in migrated core modules): PASS- Verified zero
use ... fastlyimports remain anywhere undercrates/trusted-server-core/src/
Blocking: - select(): return Err(PlatformError::HttpClient) when get_backend_name() returns None instead of silently propagating "" and losing bid correlation - Remove dead certificate_check: bool from predict_integration_backend_name; hardcode true inside to match ensure_integration_backend_with_timeout so predict/ensure cannot silently diverge and break orchestrator correlation Non-blocking: - Fix duplicate enable_ssl().sni_hostname() in BackendConfig::ensure; call once unconditionally, then add check_certificate() conditionally - Add debug_assert!(false) in to_fastly_response Stream arm to catch caller misuse in debug production builds; gated with #[cfg(not(test))] so the behavior-documentation test still passes - Add integration-route assertion to edgezero_missing_consent_store test: GET /integrations/datadome/tags.js must not return 503 when consent KV is misconfigured, locking in that integration proxy bypasses consent gating - Rename AppState.kv_store -> default_kv_store to signal it is only the fallback when no per-route consent KV override applies
Conflicts resolved: - app.rs: keep PR15's default_kv_store field rename; use PR14's build_state_from_settings in the test helper - compat.rs (modify/delete): accept PR15 deletion — file was relocated to the adapter crate as part of removing fastly from core - adserver_mock.rs, aps.rs, prebid.rs: PR15 wins — use ensure_integration_backend_with_timeout for auction-scoped timeouts and keep predict_integration_backend_name import - sourcepoint.rs: merge both sides — keep ensure_integration_backend (PR15, CDN proxy backend) and collect_response_bounded (PR14, streaming response fix); add missing None timeout arg - proxy.rs: PR15 wins on import; add enforce_max_body_size from PR14 (DEFAULT_FIRST_BYTE_TIMEOUT already available via platform module) - mod.rs: use PR15's integration_backend_spec helper in ensure_integration_backend body; honor PR14's Option<Duration> param by passing it through to the helper
|
All round-1 findings resolved in commit 72ddc42. Blocking — fixed
Non-blocking — addressed
Deferred (acknowledged)
CI: |
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review of PR 15 (remove fastly from trusted-server-core), reviewed against its actual base feature/edgezero-pr14-entry-point-dual-path to isolate this PR's 32-file changeset. Round-1 findings are addressed (select() None→Err, predict/ensure unified via integration_backend_spec, integration-route consent-bypass test, default_kv_store rename). One requested change remains: the tokio test-migration is half-done and leaves the codebase with two inconsistent async-test conventions. The remaining items are non-blocking.
Blocking
🔧 wrench
- Incomplete tokio removal: GTM tests converted to
block_on(~672 lines) butproxy.rsstill uses#[tokio::test]andtokioremains a dev-dependency — finish the conversion + drop the dep, or revert the churn. (Cargo.toml:79, google_tag_manager.rs, proxy.rs:1520)
Non-blocking
🤔 thinking
from_fastly_requestnow panics on unparseable URL: changed from"/"fallback to.expect(); confirm intentional. (adapter/compat.rs:15)
🌱 seedling
- Speculative
getrandom/uuidjsdeps forwasm32-unknown-unknown, a target no CI job builds. (core/Cargo.toml:56)
⛏ nitpick
- Stale
fastly::doc-comment references missed by the cleanup commit:proxy.rs:1485,proxy.rs:2386(fastly::Response),platform/mod.rs:28(fastly::Body).streaming_processor.rswas updated to "any platform body type"; these were missed.
CI Status
The PR's GitHub CI ran only the 3 integration-test jobs (it targets a feature branch, so the standard gates didn't trigger). Verified locally against the PR head:
- fmt: PASS
- clippy (
--all-targets --all-features -D warnings): PASS - rust tests: PASS (core 950, adapter 54)
- wasm32-wasip1 release build: PASS
Migrates ec/auth.rs, ec/batch_sync.rs, and ec/identify.rs from fastly::Request/Response to http::Request<EdgeBody>/Response<EdgeBody>. Updates the adapter entry point (main.rs) to extract DeviceSignals before the fastly→http conversion and pass them as a new parameter to route_request. Fixes adapter and core tests broken by the merge: - Replace [edge_cookie] secret_key with [ec] passphrase in all test TOML fixtures (app.rs, route_tests.rs, google_tag_manager.rs) - Update route_tests.rs to match PR14 semantics: rename test to routes_use_request_local_consent, remove stale consent-store 503 assertions, use /_ts/admin path - Switch dispatch_auth_rejected_401_carries_finalize_headers to use routes_for_state with test settings so handler regex covers /admin path - Remove unused from_fastly_response from compat.rs - Fix mut variable, orphaned doc comment, and missing # Panics sections flagged by clippy - Mark get_or_generate_ec_id as #[cfg(test)] (test-only wrapper)
Convert all remaining #[tokio::test] tests to futures::executor::block_on across proxy.rs, publisher.rs, auction/endpoints.rs, auction/orchestrator.rs, and integrations/testlight.rs. Drop tokio from [dev-dependencies] in trusted-server-core/Cargo.toml — tokio is no longer referenced anywhere in the crate. Also fix two stale doc comments in proxy.rs that still referenced fastly::Response and platform_response_to_fastly.
|
Addressing the findings from round-4 review: 🔧 Blocking — Incomplete tokio removalFixed in The conversion was broader than just
🤔 Non-blocking —
|
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review of PR 15 against HEAD cedea8b1, diffed against its actual base feature/edgezero-pr14-entry-point-dual-path. The previously blocking item — incomplete tokio removal — is resolved: 0 #[tokio::test] remain, tokio is gone from core's manifest, and the GTM conversion is lossless (9→9 tests, 14→14 assertions, 10→10 awaits). Stale fastly:: doc references are fixed.
This pass surfaced four new issues, two blocking. The core refactor mechanics (compat/backend relocation, platform-abstraction threading, consent-route fail-closed 503 wiring, deterministic backend naming) are sound and well-covered — those are not repeated here.
Blocking
🔧 wrench
from_fastly_requestpanics on an unparseable URL — regressed from a graceful"/"fallback to.expect(), on the default legacy path. (adapter/compat.rs:15)- Duplicate, IPv6-divergent EC-ID generator —
edge_cookie.rsnow carries its own HMAC generator whose/64normalization disagrees with canonicalec::generation::normalize_ip; same passphrase ⇒ IPv4 IDs match but IPv6 IDs diverge, minting non-correlating identities. (edge_cookie.rs:39vsec/generation.rs:35) - Consent-KV read-fallback / write-on-change advertised but unwired —
ConsentPipelineInput.{ec_id,kv_store}andload_consent_from_kv/save_consent_to_kvare dead in production;build_consent_contextignores the fields. (consent/mod.rs:82,storage/kv_store.rs)
❓ question
- PR goal unmet:
trusted-server-corestill depends onfastly—core/Cargo.toml:25still declares it, kept alive byec/kv.rs(fastly::kv_store) andec/rate_limiter.rs(fastly::erl). The changes-table claim that core'sfastlydependency is removed is currently false — is the EC KV/ERL migration deferred?
Non-blocking
🏕 camp site
- Orphaned
crates/trusted-server-core/src/backend.rs—lib.rsdroppedpub mod backend;, but the ~16 KB file is still tracked, no longer compiled, and still carriesuse fastly::backend::Backend. Should begit rm'd alongside thelib.rschange.
📝 note
- Duplicated
DEFAULT_FIRST_BYTE_TIMEOUT— added atplatform/mod.rs:58while an identicalpub(crate)const remains in the orphanedbackend.rs:37. Collapses to one definition once the dead file above is removed. - Removed
lgtm[rust/cleartext-logging]suppressions inpublisher.rs— if CodeQL/lgtm still runs in CI, confirm dropping these doesn't re-introduce cleartext-logging alerts on the affected debug logs.
CI Status
The PR's GitHub CI ran only the 3 integration-test jobs (it targets a feature branch, so the standard fmt/clippy/test gates didn't trigger). All 3 PASS.
- integration tests: PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
Reconciles PR14's EdgeZero EC parity work with PR15's fastly-removal refactor: - EC request-state prelude (build_ec_request_state) now reads cookies and device signals from the core http request directly — no fastly request conversion — and passes RuntimeServices to EcContext::read_from_request_with_geo per the PR15 signature - identify/batch-sync handlers call the de-fastly-ed core APIs directly (no compat round-trips); device classification on the EdgeZero path is UA-only, matching the signals available after legacy request conversion - ec_finalize_response runs on the http response before the fastly conversion in edgezero_main, mirroring PR15's legacy ordering; EcFinalizeState carries the per-request RuntimeServices so pull sync reuses the same platform HTTP client - PR15's consent-KV fail-closed wiring (runtime_services_for_consent_route) is preserved in both the auction named route and the publisher fallback - NAMED_ROUTES keeps the /_ts admin routes plus legacy aliases, the EC API routes, and the publisher-fallback rows; extract_cookie_value keeps the PR15 HttpRequest signature, now pub(crate) for app.rs - Test helpers merged: consent-store fixtures from PR15 plus PR14's absolute-URI empty_request and test_router
Blocking: - Restore the non-panicking '/' fallback in from_fastly_request: a URL Fastly accepts but http::Uri rejects degrades with a warning instead of aborting the Wasm instance. Adds a regression test using a >65534-byte URL (http::Uri's length limit; url::Url has none) - Deduplicate the EC ID generator: edge_cookie.rs delegates to the canonical ec::generation normalize_ip + generate_ec_id, removing the IPv6 /64 normalization divergence that minted non-correlating identity prefixes. Adds a test asserting both paths hash to the same prefix - Wire consent KV read-fallback and write-on-change into build_consent_context: loads persisted consent when the request carries no signals (jurisdiction re-derived from current geo) and persists cookie-sourced consent after the context is built. Adds three pipeline-level tests with an in-memory KV store Non-blocking: - git rm the orphaned trusted-server-core/src/backend.rs (no longer compiled since lib.rs dropped the module), collapsing the duplicated DEFAULT_FIRST_BYTE_TIMEOUT to the platform definition - Restore the two lgtm[rust/cleartext-logging] suppressions in publisher.rs — CodeQL still runs in CI (.github/workflows/codeql.yml) - Wrap prebid backend resolution errors in TrustedServerError::Auction with the endpoint, matching aps and adserver_mock attribution - Log a warning when an EC Set-Cookie header value is rejected instead of silently no-opping (set_ec_cookie and expire_ec_cookie) - Replace the inline block_on(select(vec![...])) + .ready in pull sync with the equivalent http_client().wait() helper
The EC KV identity graph requires compare-and-swap semantics (InsertMode::Add and generation preconditions) that the EdgeZero KvStore trait does not expose, and the rate limiter uses fastly::erl, which has no EdgeZero abstraction. Removing the dependency is deferred until EdgeZero grows equivalent APIs; note this on the manifest entry so the deferral is discoverable.
|
Re the review-body items without inline threads (all in 32d37db / 711dd6c):
Also note: the branch now includes the merge of the updated PR14 base (f8df5b7), which reconciles PR14's EdgeZero EC parity work with this PR's de-fastly-ed core APIs. Local verification on the merged head: fmt clean, clippy -D warnings clean, 62/62 adapter and 1237/1237 core tests pass. |
aram356
left a comment
There was a problem hiding this comment.
Summary (re-review)
The three prior-round findings are resolved: tokio is fully removed from core (all #[tokio::test] converted to block_on, dep dropped), the stale fastly:: doc comments are gone, and from_fastly_request reverted to the graceful "/" fallback. All local gates pass (see CI Status).
However, a merge of the latest PR14 (EC-identity port) reintroduced a hard fastly dependency in core (711dd6cb), so the PR no longer matches its own title/description. That, plus a guard that no longer guards and a now-unreachable target block, are the requested changes. The underlying engineering deferral is defensible — the asks are about accuracy and consistency, not the code's behavior.
Blocking
🔧 wrench
- PR no longer removes fastly from core;
Closes #496is inaccurate.ec/kv.rs(fastly::kv_store::{InsertMode, KVStore}+KVStoreError) andec/rate_limiter.rs(fastly::erl) still import the Fastly SDK, andCargo.tomlre-addsfastlyunconditionally. Issue #496's Done when is "Core has zerofastlyimports." Either abstract those two EC usages behind platform traits, or correct the title/body and dropCloses #496(rescope the residual under #495, which the in-code comment already references). (core/Cargo.toml:29, ec/kv.rs:14, ec/rate_limiter.rs:8) migration_guards.rsgives false assurance. The PR body says the no-fastly invariant is "enforc[ed] withmigration_guards.rs," but its regex only bansfastly::(Request|Response|http::Method|StatusCode|mime)and scans a hardcodedsourceslist that excludesec/kv.rsandec/rate_limiter.rs. It neither catches the reintroduced usage nor enforces "no fastly." Broaden it (with an explicit allowlist for the deferred EC files) or soften the claim. (migration_guards.rs:27, migration_guards.rs:48)
Non-blocking
🤔 thinking
- The
wasm32-unknown-unknownjs dependency block is now unreachable. Core has an unconditionalfastlydep (fastly only builds forwasm32-wasip1), so core can never compile forwasm32-unknown-unknown— the exact target thegetrandom/uuidjsblock exists for. Gatefastlybehind a target/feature cfg, or drop the speculative block until core can actually target Workers. (#496 listswasm32-unknown-unknownas an intended core target, so this tension is in-scope.) (core/Cargo.toml:61)
📝 note
- Diff is inflated by a stale PR14 merge. The
ec/*,proxy.rs, andpublisher.rsdeltas are largely PR14's EC port at an older revision than PR14's current tip, not PR15 changes. Re-merging the latest PR14 base would shrink the diff considerably and isolate this PR's actual contribution. Not a code defect.
CI Status
The PR's GitHub CI ran only the 3 integration-test jobs (it targets a feature branch). Verified locally against head 711dd6cb:
- fmt: PASS
- clippy (
--all-targets --all-features -D warnings): PASS - rust tests: PASS (core 1237, adapter 62)
- wasm32-wasip1 release build: PASS
| cookie = { workspace = true } | ||
| derive_more = { workspace = true } | ||
| error-stack = { workspace = true } | ||
| # Still required by ec/kv.rs (KV Store compare-and-swap via InsertMode + |
There was a problem hiding this comment.
🔧 wrench — This comment correctly documents the deferral, but it also confirms the PR no longer does what its title and description say.
Core still imports the Fastly SDK in ec/kv.rs (fastly::kv_store::{InsertMode, KVStore}, lines ~14 + KVStoreError matches) and ec/rate_limiter.rs (fastly::erl), and this manifest re-adds fastly unconditionally. The PR title ("Remove fastly dependency from trusted-server-core"), the body ("Removes all fastly crate imports from trusted-server-core"), and Closes #496 are all now inaccurate — #496's Done when is literally "Core has zero fastly imports."
The deferral itself is reasonable (EdgeZero's KvStore trait exposes no compare-and-swap, and there's no ERL abstraction). The requested change is to make the metadata honest:
- abstract the two EC usages behind platform traits before merge, or
- update the title/body to "remove fastly from core except the EC KV/ERL subsystem" and drop
Closes #496(track the residual under Fastly entry point switch (dual-path with flag) #495, which this comment already cites).
There was a problem hiding this comment.
Acknowledged — kept the deferral and made the metadata honest instead of forcing the abstraction now.
- Scope/title/
#496: title and body now read "remove fastly from core except the EC KV/ERL subsystem." DroppedCloses #496; the body now states this only partially addresses Remove fastly from core crate #496 and rescopes the residualec/kv.rs(CAS viaInsertMode) +ec/rate_limiter.rs(fastly::erl) removal under Fastly entry point switch (dual-path with flag) #495, which the in-code comment already references. - Guard now actually guards:
migration_guards.rswas broadened from the oldfastly::(Request|Response|...)regex to\b(?:use\s+fastly\b|fastly::)and now scans the full core source list (includingec/*), with an explicit allowlist forec/kv.rs+ec/rate_limiter.rs. A second test (deferred_ec_fastly_allowlist_still_tracks_actual_residual_dependencies) asserts those two files still genuinely import the SDK, so the allowlist can't silently rot once the dependency is finally removed.
Rationale for deferring the abstraction: EdgeZero's KvStore trait exposes no compare-and-swap / generation precondition, and there's no ERL equivalent yet — abstracting both would expand this PR well beyond the core type migration.
There was a problem hiding this comment.
Follow-up: verified the deferral against current EdgeZero main (HEAD 7ec2ad1) rather than asserting it.
- KV CAS still absent.
edgezero-core'sKvStoretrait exposes onlyget_bytes/put_bytes/put_bytes_with_ttl/delete/list_keys_page— no generation/CAS, no per-key metadata, noInsertMode::Add(atomic create-if-absent), andKvErrorhas no precondition-failed variant. There is a newKvHandle::read_modify_write, but its own doc states it is not atomic ("concurrent calls on the same key may cause lost writes … use only when eventual consistency is acceptable").ec/kv.rsrelies on atomic generation-matched CAS for tombstone revive and partner-ID merges, so RMW can't back it without dropping writes. - No ERL/rate-counter abstraction exists in EdgeZero at all (
grep RateCounter|erl|rate_limit|CounterDuration→ no hits).
So removing the EC fastly usage still requires an upstream EdgeZero contract that doesn't exist yet (and Cloudflare KV has no native CAS, which is the underlying design constraint). Residual stays tracked under #495.
Note: the rate-limiter half is independently movable — RateLimiter is already a core trait and only FastlyRateLimiter is Fastly-bound, so that impl can relocate to the adapter without any EdgeZero change. Can be split into its own PR if preferred; it's out of scope for this type-migration PR.
…t-dual-path' into feature/edgezero-pr15-remove-fastly-core
Summary
fastlycrate imports fromtrusted-server-coreexcept the deferred EC KV/ERL subsystem (ec/kv.rscompare-and-swap viaInsertMode+ generation preconditions, andec/rate_limiter.rsEdge Rate Limiting), which EdgeZero does not yet expose equivalents for.migration_guards.rsenforces the invariant with an explicit allowlist for those two files (residual removal tracked in Fastly entry point switch (dual-path with flag) #495)trusted-server-adapter-fastlyRuntimeServices,PlatformBackendSpec,PlatformKvStore) for core request handling instead of Fastly SDK types/auctionand publisher fallback routes, matching the legacy path's fail-closed503behavior when the store is unavailableChanges
crates/trusted-server-core/src/compat.rscrates/trusted-server-core/src/storage/crates/trusted-server-core/src/geo.rscrates/trusted-server-core/src/storage/kv_store.rsPlatformKvStorerather than Fastly KV typescrates/trusted-server-core/src/consent/mod.rsConsentPipelineInputaccepts an optionalPlatformKvStorereference for KV fallback/write-throughcrates/trusted-server-core/src/platform/crates/trusted-server-core/src/integrations/mod.rscrates/trusted-server-core/src/integrations/{aps,adserver_mock,prebid}.rscrates/trusted-server-core/src/publisher.rsRuntimeServices/PlatformKvStorefor consent KV fallback and revocation deletioncrates/trusted-server-core/src/migration_guards.rsfastlyin core" with a broadened regex over the full core source list, plus an explicit allowlist for the deferredec/kv.rs+ec/rate_limiter.rsand a test asserting the allowlist still tracks real residual usagecrates/trusted-server-core/Cargo.tomlfastlyonly for the deferred EC KV/ERL subsystem (ec/kv.rs,ec/rate_limiter.rs); full removal tracked in #495crates/trusted-server-adapter-fastly/src/compat.rscrates/trusted-server-adapter-fastly/src/backend.rscrates/trusted-server-adapter-fastly/src/platform.rsopen_kv_storeforPlatformKvStorecrates/trusted-server-adapter-fastly/src/app.rscrates/trusted-server-adapter-fastly/src/main.rscrates/trusted-server-adapter-fastly/Cargo.tomlTracking
fastlyimports reduced to the deferred EC KV/ERL subsystem). This PR intentionally does not close Remove fastly from core crate #496, sinceec/kv.rsandec/rate_limiter.rsstill import the Fastly SDK.Test plan
cargo test -p trusted-server-adapter-fastly edgezero_missing_consent_store_breaks_only_consent_routescargo test -p trusted-server-adapter-fastly configured_missing_consent_store_only_breaks_consent_routescargo test -p trusted-server-core --libcargo fmt --all -- --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspacecd crates/js/lib && npx vitest runcd crates/js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute serveChecklist
unwrap()in production code; usesexpect("should ...")where neededlogmacros rather thanprintln!